"""
面向对象
1.封装
2.继承
3.多态
"""

"""
封装：
    对外部隐藏对象的内部实现细节，仅提供有限的接口来与对象进行交互，这样可以增强代码的安全性和可维护性

封装的优点
    数据隐藏：防止外部代码直接访问和修改对象的内部数据，避免数据被意外修改，提高数据的安全性。
    可维护性：将数据和操作封装在类中，当内部实现发生变化时，只要公共接口不变，外部代码就不需要修改，降低了代码的耦合度。
    复用性：封装好的类可以在不同的地方重复使用，提高了代码的复用性。
"""
# 1.封装简单实现
    # 在这个例子中，name 和 age 是 Person 类的属性，introduce 是操作这些属性的方法。
    # 属性和方法都被封装在 Person 类中。
class Person:
    def __init__(self, name, age):
        # 初始化属性（构造函数）
        self.name = name
        self.age = age

    def introduce(self):
        # 定义方法来操作属性
        print(f"我叫 {self.name}，今年 {self.age} 岁。")


# 创建对象
p = Person("张三", 25)
# 调用方法
p.introduce()

# 2.私有属性
# 在属性名前加双下划线 __，可以将属性变为私有属性，从类的外部无法直接访问，只能通过公共方法访问私有属性
# 在这个例子中，__score 是私有属性，外部无法直接访问，只能通过 get_score 和 set_score 这两个公共方法来访问和修改。
class Student:
    def __init__(self, name, score):
        self.name = name
        # 私有属性
        self.__score = score

    def get_score(self):
        # 提供公共方法来访问私有属性
        return self.__score

    def set_score(self, new_score):
        # 提供公共方法来修改私有属性
        if 0 <= new_score <= 100:
            self.__score = new_score
        else:
            print("分数不合法。")


s = Student("李四", 85)
# 无法直接访问私有属性
# print(s.__score)  # 这行代码会报错
# 通过公共方法访问私有属性
print(s.get_score())
# 通过公共方法修改私有属性
s.set_score(90)
print(s.get_score())


"""
继承
    允许一个类（子类/派生类）获取另一个类（父类/基类）的属性和方法，并扩展或修改他们
作用：增强代码的可复用性和可扩展性
类型：单继承、多继承、方法重写（父类和子类方法重名）
扩展**** ：
    方式1：父类名.属性名/方法名（self）
    方式2：super().属性名/方法名

"""

# 1.单继承
    # ChildClass 继承自 ParentClass，这意味着 ChildClass 的实例可以使用 ParentClass 中定义的方法，同时还能使用自身定义的方法。
class ParentClass:
    # 父类的属性和方法
    def parent_method(self):
        print("这是父类的方法")

class ChildClass(ParentClass):
    # 子类可以添加自己的属性和方法
    def child_method(self):
        print("这是子类的方法")

# 创建子类的实例
child = ChildClass()
child.parent_method() # 调用父类的方法
child.child_method() # 调用子类的方法

# 2. 多继承
    # Child 类继承自 Parent1 和 Parent2 两个父类，因此它的实例可以调用这两个父类的方法
class Parent1:
    def method1(self):
        print("这是父类 1 的方法")

class Parent2:
    def method2(self):
        print("这是父类 2 的方法")

class Child(Parent1, Parent2):
    pass

# 创建子类的实例
child = Child()
child.method1() # 调用父类 1 的方法
child.method2() # 调用父类 2 的方法

# 3. 方法重写
    # 子类可以对父类中已有的方法进行重写，也就是在子类中定义一个和父类同名的方法，这样在调用该方法时，会优先使用子类中的方法
class Parent:
    producer = "马嘉璐"
    def say_hello(self):
        print("Hello from parent")

class Child(Parent):
    producer = "巫明瑾"  # 继承后复写属性
    def say_hello(self):
        print("Hello from child")

# 创建子类的实例
child = Child()
print(child.producer)   # 巫明瑾
child.say_hello() # 调用重写后的方法 "Hello from child"

# 4.** 在父类基础上扩展（2种）
    # 方式一：父类名.属性名/方法名（self）
class Parent:
    producer = "马嘉璐"
    def say_hello(self):
        print("Hello from parent")

class Child(Parent):
    producer = "巫明瑾"
    def say_hello(self):
        producer = Parent.producer # 调用父类的 属性
        Parent.say_hello(self)# 调用父类的 say_hello 方法
        print(f"Hello from child:{producer}")  # 再做扩展

# 创建子类的实例
child = Child()
child.say_hello() # 调用重写后的方法 Hello from parent \n Hello from child:马嘉璐

# ** super()
    # 方式二：super().属性名/方法名

class Parent:
    producer = "马嘉璐"
    def say_hello(self):
        print("Hello from parent")

class Child(Parent):
    producer = "巫明瑾"
    def say_hello(self):
        producer = super().producer # 调用父类的 属性
        super().say_hello() # 调用父类的 say_hello 方法
        print(f"Hello from child:{producer}")  # 再做扩展

# 创建子类的实例
child = Child()
child.say_hello() # 调用重写后的方法 Hello from parent \n Hello from child:马嘉璐



"""
3.多态：不同的对象调同一方法，得到不同的结果
（1） 通过继承和方法重写实现多态
（2）通过鸭子类型实现多态
（3）抽象类
    抽象方法：空实现（pass）
    抽象是隐藏复杂的实现细节，只暴露简单的接口，通过抽象类，可以在子类中定义实现
    抽象类不能直接实例化，只能作为子类的基类
"""
#（1）通过继承和方法重写实现多态
# Animal 是父类，Dog 和 Cat 是子类，它们都重写了 speak 方法。animal_speak 函数接受一个 Animal 类型的参数，调用其 speak 方法。
# 当传入 Dog 或 Cat 对象时，会根据对象的实际类型调用相应的 speak 方法，这就是多态的体现。
class Animal:
    def speak(self):
        pass


class Dog(Animal):
    def speak(self):
        return "汪汪汪"


class Cat(Animal):
    def speak(self):
        return "喵喵喵"


def animal_speak(animal):
    print(animal.speak())


dog = Dog()
cat = Cat()

animal_speak(dog)
animal_speak(cat)

# （2）通过鸭子类型实现多态
    # Car 和 Bike 类都有 move 方法，start_move 函数可以接受任何具有 move 方法的对象，并调用该方法。
    # 这里不关心对象是 Car 还是 Bike，只关心对象是否有 move 方法，这就是鸭子类型的多态
class Car:
    def move(self):
        print("汽车在行驶")


class Bike:
    def move(self):
        print("自行车在骑行")

def start_move(vehicle):
    vehicle.move()

car = Car()
bike = Bike()

start_move(car)
start_move(bike)

# （3） 使用抽象基类和抽象方法

# Shape 是抽象基类，area 是抽象方法。Square 和 Circle 类继承自 Shape 类，并实现了 area 方法。
# print_area 函数可以接受任何 Shape 子类的对象，并调用其 area 方法，实现了多态
from abc import ABC, abstractmethod


class Shape(ABC):
    @abstractmethod
    def area(self):
        pass


class Square(Shape):
    def __init__(self, side):
        self.side = side

    def area(self):
        return self.side * self.side


class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14 * self.radius * self.radius


def print_area(shape):
    print(shape.area())


square = Square(5)
circle = Circle(3)

print_area(square)
print_area(circle)
